package com.automotive.can1939.can;

import com.automotive.can1939.model.J1939Frame;

import java.util.HashMap;
import java.util.Map;

import static com.automotive.can1939.can.J1939Constants.*;

/**
 * J1939协议数据解析器
 * 基于SAE J1939标准解析参数组号(PGN)和可疑参数号(SPN)
 */
public class J1939DataParser {
    
    /**
     * J1939解析结果类
     */
    public static class J1939ParseResult {
        private String pgnName;
        private String spnName;
        private String value;
        private String unit;
        private String description;
        private int pgn;
        private int spn;
        
        public J1939ParseResult(int pgn, String pgnName, int spn, String spnName, 
                                String value, String unit, String description) {
            this.pgn = pgn;
            this.pgnName = pgnName;
            this.spn = spn;
            this.spnName = spnName;
            this.value = value;
            this.unit = unit;
            this.description = description;
        }
        
        // Getters
        public String getPgnName() { return pgnName; }
        public String getSpnName() { return spnName; }
        public String getValue() { return value; }
        public String getUnit() { return unit; }
        public String getDescription() { return description; }
        public int getPgn() { return pgn; }
        public int getSpn() { return spn; }
        
        @Override
        public String toString() {
            return String.format("%s - %s: %s %s (%s)", pgnName, spnName, value, unit, description);
        }
    }
    
    // J1939标准PGN定义
    private static final Map<Integer, String> PGN_NAMES = new HashMap<>();
    
    static {
        // 发动机相关PGN
        PGN_NAMES.put(PGN_EEC1, "电子发动机控制器1 (EEC1)");
        PGN_NAMES.put(PGN_EEC2, "电子发动机控制器2 (EEC2)");
        PGN_NAMES.put(PGN_EEC3, "电子发动机控制器3 (EEC3)");
        PGN_NAMES.put(PGN_ENGINE_TEMPERATURE_1, "发动机温度1 (ET1)");
        PGN_NAMES.put(PGN_AMBIENT_CONDITIONS, "环境条件 (AMB)");
        PGN_NAMES.put(PGN_INTAKE_TEMPERATURE_PRESSURE_1, "进气温度/压力1 (IC1)");
        PGN_NAMES.put(PGN_VEHICLE_ELECTRICAL_POWER_1, "车辆电气功率1 (VEP1)");
        PGN_NAMES.put(PGN_FAN_DRIVE, "风扇驱动 (FD)");
        
        // 传动系统PGN
        PGN_NAMES.put(PGN_ETC1, "电子传动控制器1 (ETC1)");
        PGN_NAMES.put(PGN_ETC2, "电子传动控制器2 (ETC2)");
        PGN_NAMES.put(PGN_TRANSMISSION_CONFIGURATION, "传动配置 (TCFG)");
        
        // 车辆动态PGN
        PGN_NAMES.put(PGN_CRUISE_CONTROL_VEHICLE_SPEED, "巡航控制/车辆速度 (CCVS)");
        PGN_NAMES.put(PGN_EBC1, "电子制动控制器1 (EBC1)");
        PGN_NAMES.put(PGN_EBC2, "电子制动控制器2 (EBC2)");
        PGN_NAMES.put(PGN_VEHICLE_POSITION, "车辆位置 (VP)");
        
        // 仪表和显示PGN
        PGN_NAMES.put(PGN_VEHICLE_DISTANCE, "车辆距离 (VD)");
        PGN_NAMES.put(PGN_ENGINE_HOURS, "发动机小时数/转数 (HOURS)");
        PGN_NAMES.put(PGN_TIME_DATE, "时间/日期 (TD)");
        
        // 诊断PGN
        PGN_NAMES.put(PGN_DIAGNOSTIC_MESSAGE_1, "诊断消息1 (DM1)");
        PGN_NAMES.put(PGN_DIAGNOSTIC_MESSAGE_2, "诊断消息2 (DM2)");
        PGN_NAMES.put(PGN_DIAGNOSTIC_MESSAGE_3, "诊断消息3 (DM3)");
        
        // 专有PGN
        PGN_NAMES.put(PGN_PROPRIETARY_A, "专有A (Proprietary A)");
        PGN_NAMES.put(PGN_PROPRIETARY_B, "专有B (Proprietary B)");
    }
    
    /**
     * 解析J1939帧
     */
    public static J1939ParseResult parseFrame(J1939Frame frame) {
        int pgn = frame.getPgn();
        byte[] data = frame.getData();
        
        switch (pgn) {
            case PGN_EEC1: // EEC1 - 电子发动机控制器1
                return parseEEC1(frame, data);
            case PGN_EEC2: // EEC2 - 电子发动机控制器2
                return parseEEC2(frame, data);
            case PGN_ENGINE_TEMPERATURE_1: // ET1 - 发动机温度1
                return parseET1(frame, data);
            case PGN_CRUISE_CONTROL_VEHICLE_SPEED: // CCVS - 巡航控制/车辆速度
                return parseCCVS(frame, data);
            case PGN_EBC1: // EBC1 - 电子制动控制器1
                return parseEBC1(frame, data);
            case PGN_ETC1: // ETC1 - 电子传动控制器1
                return parseETC1(frame, data);
            case PGN_AMBIENT_CONDITIONS: // AMB - 环境条件
                return parseAMB(frame, data);
            case PGN_VEHICLE_DISTANCE: // VD - 车辆距离
                return parseVD(frame, data);
            case PGN_ENGINE_HOURS: // HOURS - 发动机小时数
                return parseHOURS(frame, data);
            default:
                return parseUnknownFrame(frame);
        }
    }
    
    /**
     * 解析EEC1 - 电子发动机控制器1
     * SPN 190: 发动机转速
     * SPN 102: 进气歧管1压力
     * SPN 91: 油门踏板位置
     */
    private static J1939ParseResult parseEEC1(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 190: 发动机转速 (字节3-4)
            int rpm = ((data[4] & 0xFF) << 8) | (data[3] & 0xFF);
            rpm = (int)(rpm * 0.125); // 分辨率: 0.125 rpm/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "电子发动机控制器1",
                190, "发动机转速",
                String.valueOf(rpm), "rpm",
                "当前发动机转速"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "电子发动机控制器1");
    }
    
    /**
     * 解析EEC2 - 电子发动机控制器2
     * SPN 558: 油门踏板1位置
     * SPN 559: 油门踏板2位置
     */
    private static J1939ParseResult parseEEC2(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 558: 油门踏板1位置 (字节1)
            int throttle1 = data[1] & 0xFF;
            double throttlePercent = throttle1 * 0.4; // 分辨率: 0.4%/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "电子发动机控制器2",
                558, "油门踏板1位置",
                String.format("%.1f", throttlePercent), "%",
                "油门踏板开度百分比"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "电子发动机控制器2");
    }
    
    /**
     * 解析ET1 - 发动机温度1
     * SPN 110: 发动机冷却液温度
     * SPN 175: 发动机机油温度1
     */
    private static J1939ParseResult parseET1(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 110: 发动机冷却液温度 (字节0)
            int coolantTemp = data[0] & 0xFF;
            int temperature = coolantTemp - 40; // 偏移: -40°C
            
            return new J1939ParseResult(
                frame.getPgn(), "发动机温度1",
                110, "发动机冷却液温度",
                String.valueOf(temperature), "°C",
                "发动机冷却液温度"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "发动机温度1");
    }
    
    /**
     * 解析CCVS - 巡航控制/车辆速度
     * SPN 84: 车轮速度
     * SPN 595: 巡航控制状态
     */
    private static J1939ParseResult parseCCVS(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 84: 车轮速度 (字节1-2)
            int speed = ((data[2] & 0xFF) << 8) | (data[1] & 0xFF);
            double speedKmh = speed / 256.0; // 分辨率: 1/256 km/h/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "巡航控制/车辆速度",
                84, "车轮速度",
                String.format("%.2f", speedKmh), "km/h",
                "基于车轮的车辆速度"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "巡航控制/车辆速度");
    }
    
    /**
     * 解析EBC1 - 电子制动控制器1
     * SPN 521: ABS状态
     * SPN 575: ASR状态
     */
    private static J1939ParseResult parseEBC1(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 521: ABS状态 (字节0, 位6-7)
            int absStatus = (data[0] >> 6) & 0x03;
            String absStatusText;
            switch (absStatus) {
                case 0: absStatusText = "关闭"; break;
                case 1: absStatusText = "开启"; break;
                case 2: absStatusText = "错误"; break;
                default: absStatusText = "不可用"; break;
            }
            
            return new J1939ParseResult(
                frame.getPgn(), "电子制动控制器1",
                521, "ABS状态",
                absStatusText, "",
                "防抱死制动系统状态"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "电子制动控制器1");
    }
    
    /**
     * 解析ETC1 - 电子传动控制器1
     * SPN 523: 传动输出轴转速
     * SPN 524: 传动输入轴转速
     */
    private static J1939ParseResult parseETC1(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 523: 传动输出轴转速 (字节2-3)
            int outputSpeed = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF);
            double speedRpm = outputSpeed * 0.125; // 分辨率: 0.125 rpm/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "电子传动控制器1",
                523, "传动输出轴转速",
                String.format("%.1f", speedRpm), "rpm",
                "传动系统输出轴转速"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "电子传动控制器1");
    }
    
    /**
     * 解析AMB - 环境条件
     * SPN 171: 环境空气温度
     * SPN 108: 大气压力
     */
    private static J1939ParseResult parseAMB(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 171: 环境空气温度 (字节3)
            int ambientTemp = data[3] & 0xFF;
            int temperature = ambientTemp - 40; // 偏移: -40°C
            
            return new J1939ParseResult(
                frame.getPgn(), "环境条件",
                171, "环境空气温度",
                String.valueOf(temperature), "°C",
                "车辆周围环境温度"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "环境条件");
    }
    
    /**
     * 解析VD - 车辆距离
     * SPN 244: 总车辆距离
     * SPN 245: 行程距离
     */
    private static J1939ParseResult parseVD(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 244: 总车辆距离 (字节0-3)
            long totalDistance = ((long)(data[3] & 0xFF) << 24) | 
                               ((long)(data[2] & 0xFF) << 16) |
                               ((long)(data[1] & 0xFF) << 8) | 
                               (long)(data[0] & 0xFF);
            totalDistance *= 5; // 分辨率: 5 m/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "车辆距离",
                244, "总车辆距离",
                String.valueOf(totalDistance), "m",
                "车辆总行驶距离"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "车辆距离");
    }
    
    /**
     * 解析HOURS - 发动机小时数
     * SPN 247: 总发动机小时数
     */
    private static J1939ParseResult parseHOURS(J1939Frame frame, byte[] data) {
        if (data.length >= 8) {
            // SPN 247: 总发动机小时数 (字节0-3)
            long totalHours = ((long)(data[3] & 0xFF) << 24) | 
                            ((long)(data[2] & 0xFF) << 16) |
                            ((long)(data[1] & 0xFF) << 8) | 
                            (long)(data[0] & 0xFF);
            double hours = totalHours * 0.05; // 分辨率: 0.05 h/bit
            
            return new J1939ParseResult(
                frame.getPgn(), "发动机小时数",
                247, "总发动机小时数",
                String.format("%.2f", hours), "h",
                "发动机累计运行小时数"
            );
        }
        return createInvalidDataResult(frame.getPgn(), "发动机小时数");
    }
    
    /**
     * 解析未知帧
     */
    private static J1939ParseResult parseUnknownFrame(J1939Frame frame) {
        String pgnName = PGN_NAMES.getOrDefault(frame.getPgn(), "未知PGN");
        return new J1939ParseResult(
            frame.getPgn(), pgnName,
            0, "原始数据",
            frame.getDataHexString(), "",
            "未解析的J1939数据"
        );
    }
    
    /**
     * 创建无效数据结果
     */
    private static J1939ParseResult createInvalidDataResult(int pgn, String pgnName) {
        return new J1939ParseResult(
            pgn, pgnName,
            0, "无效数据",
            "数据长度不足", "",
            "数据格式错误或长度不足"
        );
    }
    
    /**
     * 获取PGN名称
     */
    public static String getPgnName(int pgn) {
        return PGN_NAMES.getOrDefault(pgn, "未知PGN");
    }
    
    /**
     * 获取所有支持的PGN
     */
    public static Map<Integer, String> getAllSupportedPgns() {
        return new HashMap<>(PGN_NAMES);
    }
}